package mc

import (
	"fmt"
	"github.com/go-playground/validator/v10"
	"github.com/spf13/cast"
	"gorm.io/gorm"
	"reflect"
	"strings"
	"time"
)

type ModelPage struct {
	Model            *Model
	Name             string                 // 页面名称
	Items            []string               // 使用的字段名集
	Fields           map[string]*ModelField // 页面字段
	List             pageListConfig         // 列表配置
	Javascript       pageJsConfig           // js配置
	Extra            map[string]interface{} // 扩展信息
	Data             map[string]interface{} // 页面数据
	PkValue          interface{}            // pk值
	RenderUseDefault *bool                  // 是否使用默认值，如果未设置，系统根据不同情况自行选择
	UseAction        string                 // 使用的操作方法
	SearchHidden     bool                   // 是否隐藏查询
	SearchPage       *ModelPage             // 查询页
	searchPageName   string                 // 查询page key

}

type ModelField struct {
	*fieldConfig
	Value      interface{} // 值
	FromData   *FromData    // 字段来源数据
	WidgetHtml string      // widget html
}

// 数据查询选项
type QueryOption struct {
	ExtraWhere          []interface{}          // 附加的查询条件
	Values              map[string]interface{} // 查询项的值
	ExtraFields         []string               // 额外附加的查询字段
	Order               string                 // 排序
	Page                int                    // 查询页码（仅对find有效）
	PageSize            int                    // 查询记录数 （仅对find有效）
	NotTotal            bool                   // 是否不查询总记录数 （仅对find有效）
	NotSearch           bool                   // 是否不使用配置查询项进行查询
	NotCount            bool                   // 是否查询汇总项 （仅对find有效）
	TreeIndent          string                 // 树型模型节点名称前根据层级加前缀字符
	NotConvertFromValue bool                   // 不转换from值， 默认false(转换）
	AttachFromRealValue bool                   // 是否附加kv及enum字段原值
}

// 字段设置值
func (field *ModelField) setValue(value interface{}, useDefault bool) {
	// 当字段值不存在时是否使用默认值
	if IsEmpty(value) {
		if useDefault && field.Default != nil {
			field.Value = field.Default
		} else {
			field.Value = value
		}
	} else {
		field.Value = value
	}
	if field.Value != nil && (reflect.TypeOf(field.Value).Kind()==reflect.Array || reflect.TypeOf(field.Value).Kind()==reflect.Slice) {
		if field.Between || field.Multiple {
			field.Value = Join(field.Value, field.Separator)
		}
	}
}

// 各字段初始化值
func (page *ModelPage) InitValues(values map[string]interface{}, useDefault bool) *ModelPage {
	for _, field := range page.Fields {
		field.setValue(values[field.Name], useDefault)
	}
	return page
}

// 获取页面pkValue
func (page *ModelPage) GetPkValue(ctx *Context) interface{} {
	pkValue := page.PkValue
	if IsEmpty(pkValue) {
		if ctx.Request.Method != "GET" {
			pkValue = ctx.DefaultPostForm(page.Model.config.Table.Pk, "")
		}
		if IsEmpty(pkValue) {
			pkValue = ctx.DefaultQuery(page.Model.config.Table.Pk, "")
		}
	}
	return pkValue
}

// 获取页面渲染是否使用默认值
func (page *ModelPage) GetRenderUseDefault(def bool) bool {
	if page.RenderUseDefault == nil {
		return def
	} else {
		return *page.RenderUseDefault
	}

}

// 初始化来源数据
func (page *ModelPage) InitFromData() *ModelPage {
	for _, field := range page.Fields {
		if field.FromInfo != nil && field.FromData ==nil {
			field.FromData = page.Model.GetFromData(field.FromInfo)
		}
	}
	return page
}

// 初始化字段 widget html
func (page *ModelPage) InitWidget() *ModelPage {
	page.InitFromData()
	for _, field := range page.Fields {
		if field.WidgetHtml == "" {
			field.WidgetHtml = CreateWidget(field)
		}
	}
	return page
}

// 根据条件查询一条原始数据记录
// @param query 查询条件
// @param args 查询条件值
// @return data 查询结果
// @return exist 是否存在
// @return err
func (page *ModelPage) QueryOneOriginal(query interface{}, args ...interface{}) (data map[string]interface{}, exist bool, err error) {
	qo := &QueryOption{
		//ExtraWhere: []interface{}{fmt.Sprintf("%s = ? ", page.model.config.Table.Pk), pkValue},
		ExtraWhere:          make([]interface{}, 0),
		NotSearch:           true,
		NotConvertFromValue: true,
	}
	qo.ExtraWhere = append(append(qo.ExtraWhere, query), args...)
	return page.QueryOne(qo)
}

// 查询一条记录
// 不查询总记录数，不查询汇数
// @param qo 查询选项
// @return data 查询结果
// @return exist 是否存在
// @return err
func (page *ModelPage) QueryOne(qo *QueryOption) (data map[string]interface{}, exist bool, err error) {
	if qo == nil {
		qo = &QueryOption{}
	}
	qo.PageSize = 1
	qo.Page = 1
	qo.NotTotal = true
	qo.NotCount = true
	if data, _, _, err := page.Query(qo); err != nil {
		return nil, false, err
	} else if len(data) <= 0 {
		return nil, false, nil
	} else {
		return data[0], true, nil
	}
}
// 根据原生SQL语句进行查询
func (page *ModelPage) QueryRawSQL(qo *QueryOption)(data []map[string]interface{}, count map[string]interface{}, total int64, err error) {
	// 检查选项
	if qo == nil {
		qo = &QueryOption{}
	}
	db := page.Model.NewDB()
	// 分析查询条件
	page.ParseQueryWhere(db, qo)
	// 分析行权限控制条件
	page.Model.ParseRowAuthWhere(db)

	// 排序P
	if qo.Order != "" {
		qo.Order = page.OrderAddAlias(qo.Order)
		db.Order(qo.Order)
	} else if page.Model.config.Table.Order != "" {
		db.Order(page.Model.config.Table.Order)
	}

	// 分页信息
	//offset, limit :=0, 0
	//if qo.PageSize == -1 {
	//	limit = 0
	//} else {
	//	offset, limit = GetOffsetLimit(qo.Page, qo.PageSize)
	//}

	// 查询
	data = make([]map[string]interface{}, 0)
	//theDB := db.Session(&gorm.Session{})

	//if limit >= 0 {
	//	if err = theDB.Offset(offset).Limit(limit).Select(fieldNames).Find(&data).Error; err != nil {
	//		return
	//	}
	//} else {
	//	if err = theDB.Find(&data).Error; err != nil {
	//		return
	//	}
	//}
	//
	//if !qo.NotTotal {
	//	if err = theDB.Count(&total).Error; err != nil {
	//		return
	//	}
	//}
	//if !qo.NotCount && countFieldNames != nil && len(countFieldNames) > 0 {
	//	count = make(map[string]interface{})
	//	if err = db.Select(countFieldNames).Take(&count).Error; err != nil {
	//		return
	//	}
	//}
	err = page.ProcessData(data, qo)
	return

}
// 查询记录集
// @param qo 查询选项
// @return data 查询结果集
// @return count 汇总结果集
// @return total 记录数
// @return err
func (page *ModelPage) Query(qo *QueryOption) (data []map[string]interface{}, count map[string]interface{}, total int64, err error) {
	// 检查选项
	if qo == nil {
		qo = &QueryOption{}
	}
	// 分析查询的字段
	fieldNames, countFieldNames := page.ParseQueryFields(qo)
	if fieldNames == nil || len(fieldNames) <= 0 {
		return
	}

	db := page.Model.NewDB()
	// 分析查询条件
	page.ParseQueryWhere(db, qo)
	// 分析行权限控制条件
	page.Model.ParseRowAuthWhere(db)

	// 排序P
	if qo.Order != "" {
		qo.Order = page.OrderAddAlias(qo.Order)
		db.Order(qo.Order)
	} else if page.Model.config.Table.Order != "" {
		db.Order(page.Model.config.Table.Order)
	}

	// 分页信息
	offset, limit :=0, -1
	if qo.PageSize > 0 {
	//-1 {
	//	limit = -1
	//} else {
		offset, limit = GetOffsetLimit(qo.Page, qo.PageSize)
	}

	// 查询
	data = make([]map[string]interface{}, 0)
	theDB := db.Session(&gorm.Session{})

	//if limit >= 0 {
		if err = theDB.Offset(offset).Limit(limit).Select(fieldNames).Find(&data).Error; err != nil {
			return
		}
	//} else {
	//	if err = theDB.Find(&data).Error; err != nil {
	//		return
	//	}
	//}

	type r struct {
		Total int64 `json:"total,omitempty"`
	}
	rst := &r{}
	newDB := page.Model.NewDB()
	if !qo.NotTotal {
		if err = newDB.Raw("SELECT COUNT(*) as total FROM (?) AS sub", db.Select(fieldNames)).Scan(rst).Error; err != nil {
			return
		}
		total = rst.Total

		//if err = theDB.Count(&total).Error; err != nil {
		//	return
		//}
	}
	if !qo.NotCount && countFieldNames != nil && len(countFieldNames) > 0 {
		count = make(map[string]interface{})
		if err = db.Select(countFieldNames).Take(&count).Error; err != nil {
			return
		}
	}
	err = page.ProcessData(data, qo)
	return
}


// 新增记录
// @param data 待新增的数据
// @param fn 数据验证后回调
// @return rowsAffected 影响的记录数
// @return err
func (page *ModelPage) Add(values map[string]interface{}, fn func()) (rowsAffected int64, err error) {
	if values != nil {
		page.InitValues(values, true)
	}
	// 分析数据
	//data := page.ParseValues(values, true)
	// 验证数据
	if err = page.VerifyValues(); err != nil {
		return
	}
	// 数据验证后回调
	fn()
	//// 检查重复记录
	if _, _, err = page.CheckUnique(nil); err != nil {
		return
	}
	// 创建数据
	db := page.Model.BaseDB(false).Create(page.GetSaveValues())
	return db.RowsAffected, db.Error
}

// 根据pk更新记录
// @param data 待更新的数据
// @param fn 数据验证后回调
// @param oldPkValue pk字段原值
// @return rowsAffected 影响的记录数
// @return err
func (page *ModelPage) SaveByPk(data map[string]interface{}, fn func(), oldPkValue interface{}) (rowsAffected int64, err error) {
	return page.Save(data, fn, fmt.Sprintf("`%s` = ? ", page.Model.config.Table.Pk), oldPkValue)
}

// 根据条件更新记录
// @param values 待更新的数据
// @param fn 数据验证后回调
// @param query 条件 （更新时使用，新增为nil）
// @return args 条件值
// @return err
func (page *ModelPage) Save(values map[string]interface{}, fn func(), query interface{}, args ...interface{}) (rowsAffected int64, err error) {
	// 设置数据
	if values != nil {
		page.InitValues(values, false)
	}
	// 验证数据
	if err = page.VerifyValues(); err != nil {
		return
	}
	// 数据验证后回调
	fn()
	// 检查重复记录
	if _, _, err = page.CheckUnique(query, args...); err != nil {
		return
	}
	// 更新数据
	db := page.Model.BaseDB(false)
	db.Where(query, args...).Updates(page.GetSaveValues())
	return db.RowsAffected, db.Error
}

// 数据验证
func (page *ModelPage) VerifyValues() (err error) {
	for _, fieldName := range page.Items {
		field := page.Fields[fieldName]
		if field.Verify != "" {
			if err = Validate.Var(field.Value, field.Verify); err != nil {
				for _, err := range err.(validator.ValidationErrors) {
					return &Result{Message: fmt.Sprintf("【%s】%s", field.Title, err.Translate(Trans)), IsInfo: true}
				}
			}
		}
	}
	return
}

// 检查数据唯一性
// @param query 条件 （更新时使用，新增为nil）
// @return args 条件值
func (page *ModelPage) CheckUnique(query interface{}, args ...interface{}) (db *gorm.DB, exist bool, err error) {
	config := page.Model.config
	// 如果没有设置唯一字段，且主键是自增时，直接返回不重复
	if (config.Table.UniqueFields == nil || len(config.Table.UniqueFields) <= 0) && config.Table.AutoInc {
		return
	}
	// 如果待保存的数据不包含唯一性字段，则不验证
	existField := false
	for _, fieldName := range page.Items {
		field := page.Fields[fieldName]
		if !field.Disabled && InArray(fieldName, config.Table.UniqueFields) {
			existField = true
		}
	}
	if !existField {
		return
	}

	db = page.Model.BaseDB(true)
	pk := page.Model.FieldAddAlias(config.Table.Pk)

	fieldTitles := make([]string, 0)
	// 当前条件记录之外的
	if query != nil {
		db.Not(query, args...)
	}
	where := ""
	whereValue := make([]interface{}, 0)
	// 检查唯一字段
	for _, fieldName := range config.Table.UniqueFields {
		field, ok := page.Fields[fieldName]
		if !ok {
			err = &Result{Message: fmt.Sprintf("字段：%s 末在页面编辑表单中字义", fieldName), IsInfo: true}
			return
		}
		if where == "" {
			where += fmt.Sprintf(" %s = ?", page.Model.FieldAddAlias(fieldName))
		} else {
			where += fmt.Sprintf(" AND %s = ?", page.Model.FieldAddAlias(fieldName))
		}
		whereValue = append(whereValue, field.Value)
		fieldTitles = append(fieldTitles, field.Title)
	}

	// 非自增PK表，且要更新的字段包含有pk字段，则检查PK字段
	_, ok := page.Fields[config.Table.Pk]
	if !config.Table.AutoInc && ok {
		if where == "" {
			where = fmt.Sprintf("%s = ?", pk)
		} else {
			where = fmt.Sprintf("( %s ) OR ( %s )", where, fmt.Sprintf("%s = ?", pk))
		}
		whereValue = append(whereValue, page.Fields[config.Table.Pk].Value)
		fieldTitles = append(fieldTitles, config.Fields[config.fieldIndexes[config.Table.Pk]].Title)
	}
	db.Where(where, whereValue...)
	var total int64
	if err = db.Count(&total).Error; err != nil {
		return
	} else if total > 0 {
		exist, err = true, &Result{Message: fmt.Sprintf("记录已存在：【%s】存在重复", strings.Join(fieldTitles, "、")), IsInfo: true}
		return
	}
	return
}

// 获取页面字段的值集
func (page *ModelPage) GetValues() (values map[string]interface{}) {
	values = make(map[string]interface{})
	for _, fieldName := range page.Items {
		values[fieldName] = page.Fields[fieldName].Value
	}
	return
}

// 获取需要保存数据的页面字段的值集
// 过滤掉未赋值、禁止编辑、不保存的字段
func (page *ModelPage) GetSaveValues() (values map[string]interface{}) {
	values = make(map[string]interface{})
	for _, fieldName := range page.Items {
		field := page.Fields[fieldName]
		if field.Value == nil || field.Disabled || field.NoSQL { //丢弃未赋值的字段
		//if field.Value == nil || field.NoSQL { //丢弃未赋值的字段
			continue
		} else {
			values[fieldName] = field.Value
		}
	}
	return
}

// 分析查询字段
//  @param	qo		查询选项
//  @return	fields	最终需要查询的字段名数组
//  @return	countFields	汇总字段
func (page *ModelPage) ParseQueryFields(qo *QueryOption) (fieldNames []string, countFieldNames []string) {
	fieldNames = make([]string, 0)
	countFieldNames = make([]string, 0)
	// 扩展字段
	fieldNames = append(fieldNames, page.Model.FieldsAddAlias(qo.ExtraFields)...)
	//  树型必备字段
	if page.Model.IsTree() {
		fieldNames = append(fieldNames, page.Model.ParseTreeExtraField()...)
	}
	for _, fieldName := range page.Items {
		field := page.Fields[fieldName]
		if field.NoSQL { //非数据库字段，丢弃
			continue
		}
		// 基础字段
		newFieldName := ""
		if field.Alias == "" {
			newFieldName = page.Model.FieldAddAlias(fieldName)
		} else if field.Alias != "" {
			newFieldName = fmt.Sprintf("%s AS %s", field.Alias, fieldName)
		}
		fieldNames = append(fieldNames, newFieldName)

		// 汇总字段
		if field.Count != "" {
			countFieldNames = append(countFieldNames, fmt.Sprintf("%s AS %s", field.Count, fieldName))
		}
	}
	return
}

//  分析查询条件
//  @param qo 查询选项
func (page *ModelPage) ParseQueryWhere(db *gorm.DB, qo *QueryOption) {
	// 额外的查询条件
	if qo.ExtraWhere != nil {
		db.Where(qo.ExtraWhere[0], qo.ExtraWhere[1:]...)
	}

	//  模型各查询字段
	if !qo.NotSearch && page.SearchPage != nil {
		if qo.Values != nil {
			page.SearchPage.InitValues(qo.Values, false)
		}
		for _, fieldName := range page.SearchPage.Items {
			field := page.SearchPage.Fields[fieldName]
			//  该查询字段未带条件配置 或 未传值，跳过
			if IsEmpty(field.Value) {
				continue
			}
			if field.Where == "" {
				field.Where = fmt.Sprintf("%s = ?", page.Model.FieldAddAlias(fieldName))
				field.SearchValues = []string{"?"}
			}
			//  查询值与查询条件匹配
			values := make([]interface{}, 0)
			if field.Between { // 范围值
				vs := make([]string, 2)
				copy(vs[0:], cast.ToStringSlice(Split(field.Value, field.Separator))[0:])
				for i, v := range field.SearchValues {
					if v == "?" {
						values = append(values, vs[i])
					} else {
						values = append(values, strings.ReplaceAll(v, "?", vs[i]))
					}
				}
			} else { // 单个值
				for _, v := range field.SearchValues {
					if v == "?" {
						if field.Multiple {
							values = append(values, Split(field.Value, field.Separator))
						} else {
							values = append(values, field.Value)
						}
					} else {
						values = append(values, strings.ReplaceAll(v, "?", cast.ToString(field.Value)))
					}
				}
			}
			db.Where(field.Where, values...)
		}
	}
	return
}
// 排序字段加别名
func (page *ModelPage) OrderAddAlias(order string) (newOrder string){
	newOrder = order
	// 排序P
	if order != "" {
		if !strings.Contains(order, ".") { //排序加别名
			tmpOrder := strings.Split(order+" ", " ")
			if field, ok := page.Fields[strings.TrimSpace(tmpOrder[0])]; ok {
				if field.Alias != "" {
					newOrder = field.Alias + " " + tmpOrder[1]
				}
			}
		}
	}
	return
}

// 对查询结果数据进行处理
// @param data 查询结果集
// @param qo 查询选项
// @return err
func (page *ModelPage) ProcessData(data []map[string]interface{}, qo *QueryOption) (err error) {
	if data == nil || len(data) <= 0 {
		return
	}
	// 序号
	if page.List.Number {
		for i, _ := range data {
			data[i]["__mc_index"] = (qo.Page-1)*qo.PageSize + i + 1
		}
	}
	// 转换成from值
	if !qo.NotConvertFromValue {
		page.InitFromData()
	}
	for _, fieldName := range page.Items {
		if _, ok := data[0][fieldName]; !ok {
			continue
		}
		field := page.Fields[fieldName]
		// 格式化日期
		if field.TimeFormat != "" {
			for i, _ := range data {
				if t, ok := data[i][fieldName].(time.Time); ok {
					data[i][fieldName] = t.Format(field.TimeFormat)
				}
			}
		}
		// 格式化文本
		if field.Format != "" {
			for i, _ := range data {
				data[i][fieldName] = fmt.Sprintf(field.Format, data[i][fieldName])
			}
		}
		// 转化来源数据
		if field.FromInfo != nil && !qo.NotConvertFromValue {
			for i, _ := range data {
				if qo.AttachFromRealValue { // 附加字段原值真实值
					data[i]["__mc_"+fieldName] = data[i][fieldName]
				}
				vString := cast.ToString(data[i][fieldName]) // 字段值
				if field.Multiple {                          // 多选
					vs := strings.Split(vString, field.Separator)
					newVs := make([]string, 0)
					for _, v := range vs {
						newVs = append(newVs, cast.ToString(field.FromData.List[v]["__mc_value"]))
					}
					data[i][fieldName] = strings.Join(newVs, field.Separator)
				} else { // 单选
					data[i][fieldName] = cast.ToString(field.FromData.List[vString]["__mc_value"])
				}
			}
		}
	}

	// 树形
	if page.Model.IsTree() && qo.TreeIndent != "" { // 树形名称字段加前缀
		for i, _ := range data {
			data[i][page.Model.config.Tree.NameField] = RepeatString(qo.TreeIndent, cast.ToInt(data[i]["__mc_level"])-1) + cast.ToString(data[i][page.Model.config.Tree.NameField])
		}
	}
	return
}

// 时间字段获取时间值
func (field *ModelField) GetTime() (t time.Time, err error) {
	if field.TimeFormat == "" {
		err = fmt.Errorf("%s 字段未配置time_format属性", field.Name)
		return
	}
	t, err = time.Parse(field.TimeFormat, cast.ToString(field.Value))
	return
}
